package com.sojson.util.token;

import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.sojson.base.impl.Base;
import com.sojson.base.impl.BaseUser;
import com.sojson.enums.core.ELoginDeviceType;
import com.sojson.enums.core.ELoginMoreOnlineType;
import com.sojson.util.ExpUtil;
import com.sojson.util.param.ParamUtil;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

/**
 * Token
 * 
 * @author liu
 * @date 2021-03-16
 */
@ApiModel("Token")
public class Token extends Base implements UserDetails {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    /** Token的唯一标识 */
    @ApiModelProperty("Token的ID")
    private String id;
    @ApiModelProperty("用户信息")
    private BaseUser user;
    @ApiModelProperty("用户角色ID信息")
    private Set<String> roleIds;
    @ApiModelProperty("用户可操作的角色ID信息")
    private Set<String> roleIdsExist;
    @JSONField(serialize = false)
    @JsonIgnore
    @ApiModelProperty("用户最新角色ID信息")
    private Set<String> roleIdsNew;
    @JSONField(serialize = false)
    @JsonIgnore
    @ApiModelProperty("用户角色信息")
    private Set<String> roles;
    @JSONField(serialize = false)
    @JsonIgnore
    @ApiModelProperty("用户权限信息")
    private Set<String> permissions;
    @JSONField(serialize = false)
    @JsonIgnore
    @ApiModelProperty("用户权限ID信息")
    private Set<String> permIds;
    @ApiModelProperty("用户部门信息")
    private Set<String> depts;
    @ApiModelProperty("供SpringSecurity使用的权限集合")
    private List<GrantedAuthority> authorities;
    @ApiModelProperty("登录环境(web_admin:后台管理员,web_merchant:后台商户,app_user:App用户,xcx_user:小程序用户)")
    private String loginEnv;
    @ApiModelProperty("登录设备类型(1:电脑登录,2:手机登录)")
    private Integer typeLoginDevice;
    @ApiModelProperty("登录设备类型的key名称")
    private String keyLoginDevice;
    @ApiModelProperty("用户登录的类型: 1:账号密码登录,2:手机号码登录,3:QQ登录,4:微信登录,5:新浪微博登录")
    private Integer loginType;
    @ApiModelProperty("登录的主机")
    private String host;
    @ApiModelProperty("踢出状态(true:已被踢出,false:未被踢出)")
    private Boolean statusKickout = false;

    @ApiModelProperty("Token 创建时间")
    private Long startTime;
    @ApiModelProperty("Token 登录时间")
    private Long loginTime;
    @ApiModelProperty("Token 最后交互时间")
    private Long lastAccess;
    @ApiModelProperty("Token 过期时间")
    private Long expireTime;
    @ApiModelProperty("Token 下一次过期时间")
    private Long expireTimeNext;

    /** 构造方法 */
    public Token() {}

    /** 构造方法 */
    public Token(BaseUser user) {
        setUser(user);
    }

    /**
     * 获取Token的唯一标识
     * 
     * @return
     */
    public String getId() {
        return id;
    }

    /**
     * 设置Token的唯一标识
     * 
     * @param id
     */
    public void setId(String id) {
        this.id = id;
    }

    /**
     * 获取用户信息
     * 
     * @return
     */
    public BaseUser getUser() {
        return user;
    }

    /**
     * 设置用户信息
     * 
     * @param user
     */
    public void setUser(BaseUser user) {
        this.user = user;
    }

    /**
     * 获取用户角色ID信息
     * 
     * @return
     */
    public Set<String> getRoleIds() {
        return roleIds;
    }

    /**
     * 设置用户角色ID信息
     * 
     * @param roleIds
     */
    public void setRoleIds(Set<String> roleIds) {
        this.roleIds = roleIds;
    }

    /**
     * 获取用户最新角色ID信息
     * 
     * @return
     * @throws IOException 
     */
    public Set<String> getRoleIdsNew() throws IOException {
        // 角色存在就返回
        if (roleIdsNew != null) {
            return roleIdsNew;
        }

        // 通过ID查找角色
        Set<String> keys = new HashSet<>();
        for (String roleId : roleIds) {
            if (TokenUtil.ROLE_KEYS.containsKey(roleId)) {
                keys.add(roleId);
            }
        }

        setRoleIdsNew(keys);
        return getRoleIdsNew();
    }

    /**
     * 设置用户最新角色ID信息
     * 
     * @param roles
     */
    public void setRoleIdsNew(Set<String> roleIdsNew) {
        this.roleIdsNew = roleIdsNew;
    }

    /**
     * 获取用户角色信息
     * 
     * @return
     * @throws IOException 
     */
    public Set<String> getRoles() throws IOException {
        // 角色存在就返回
        if (roles != null) {
            return roles;
        }

        // 通过ID查找角色
        setRoles(TokenUtil.getRoles(roleIds));
        return getRoles();
    }

    /**
     * 设置用户角色信息
     * 
     * @param roles
     */
    public void setRoles(Set<String> roles) {
        this.roles = roles;
    }

    /**
     * 获取用户可操作的角色ID信息
     * 
     * @return
     */
    public Set<String> getRoleIdsExist() {
        return roleIdsExist;
    }

    /**
     * 设置用户可操作的角色ID信息
     * 
     * @param roleIdsExist
     */
    public void setRoleIdsExist(Set<String> roleIdsExist) {
        this.roleIdsExist = roleIdsExist;
    }

    /**
     * 获取用户权限信息
     * 
     * @return
     * @throws IOException 
     */
    public Set<String> getPermissions() throws IOException {
        // 权限存在就返回
        if (permissions != null) {
            return permissions;
        }

        // 超级管理员返回特殊权限
        if (ParamUtil.isAdminSuper()) {
            Set<String> perms = new HashSet<>();
            perms.add(TokenUtil.ALL_PERMISSION);
            return perms;
        }
        // 非超级管理员返回对应权限
        setPermissions(TokenUtil.getPerms(roleIds));
        return getPermissions();
    }

    /**
     * 设置用户权限信息
     * 
     * @param permissions
     */
    public void setPermissions(Set<String> permissions) {
        this.permissions = permissions;
    }

    /**
     * 获取用户权限ID信息
     * 
     * @return
     * @throws IOException 
     */
    public Set<String> getPermIds() throws IOException {
        // 权限存在就返回
        if (permIds != null) {
            return permIds;
        }

        // 超级管理员返回特殊权限
        if (ParamUtil.isAdminSuper()) {
            Set<String> perms = new HashSet<>();
            perms.add(TokenUtil.ALL_PERMISSION);
            return perms;
        }

        // 非超级管理员返回对应权限
        setPermIds(TokenUtil.getPermIdsExist());
        return getPermIds();
    }

    /**
     * 设置用户权限ID信息
     * 
     * @param permIds
     */
    public void setPermIds(Set<String> permIds) {
        this.permIds = permIds;
    }

    /**
     * 获取用户部门信息
     * 
     * @return
     */
    public Set<String> getDepts() {
        return depts;
    }

    /**
     * 设置用户部门信息
     * 
     * @param depts
     */
    public void setDepts(Set<String> depts) {
        this.depts = depts;
    }

    /** 获取登录环境(web_admin:后台管理员,web_merchant:后台商户,app_user:App用户,xcx_user:小程序用户) */
    public String getLoginEnv() {
        return loginEnv;
    }

    /** 设置登录环境(web_admin:后台管理员,web_merchant:后台商户,app_user:App用户,xcx_user:小程序用户) */
    public void setLoginEnv(String loginEnv) {
        this.loginEnv = loginEnv;
    }

    /** 获取登录设备类型(1:电脑登录,2:手机登录) */
    public Integer getTypeLoginDevice() {
        return typeLoginDevice;
    }

    /** 设置登录设备类型(1:电脑登录,2:手机登录) */
    public void setTypeLoginDevice(Integer typeLoginDevice) {
        this.typeLoginDevice = typeLoginDevice;
    }

    /** 获取登录设备类型的key名称 */
    public String getKeyLoginDevice() {
        return keyLoginDevice;
    }

    /** 设置登录设备类型的key名称 */
    public void setKeyLoginDevice() {
        // 此帐号是否允许帐号在多地同时在线
        Integer moreOnline = getUser().getTypeMoreOnline();
        if (ELoginMoreOnlineType.ONE.getCode() == moreOnline) {
            this.keyLoginDevice = ELoginDeviceType.ALL.getKey();
        } else if (ELoginMoreOnlineType.NO.getCode() == moreOnline) {
            this.keyLoginDevice = ELoginDeviceType.ALL.getKey();
        } else if (ELoginMoreOnlineType.NUMBER.getCode() == moreOnline) {
            this.keyLoginDevice = ELoginDeviceType.ALL.getKey();
        } else {
            if (ELoginDeviceType.CELLPHONE.getCode() == typeLoginDevice) {
                this.keyLoginDevice = ELoginDeviceType.CELLPHONE.getKey();
            } else if (ELoginDeviceType.COMPUTER.getCode() == typeLoginDevice) {
                this.keyLoginDevice = ELoginDeviceType.COMPUTER.getKey();
            } else {
                ExpUtil.throwEx("登录设备不存在！");
            }
        }
    }

    /** 获取用户登录的类型 */
    public Integer getLoginType() {
        return loginType;
    }

    /** 设置用户登录的类型 */
    public void setLoginType(Integer loginType) {
        this.loginType = loginType;
    }

    /** 获取登录的主机 */
    public String getHost() {
        return host;
    }

    /** 设置登录的主机 */
    public void setHost(String host) {
        this.host = host;
    }

    /** 获取踢出状态(true:已被踢出,false:未被踢出) */
    public Boolean getStatusKickout() {
        return statusKickout;
    }

    /** 设置踢出状态(true:已被踢出,false:未被踢出) */
    public void setStatusKickout(Boolean statusKickout) {
        this.statusKickout = statusKickout;
    }

    /** 获取Token创建时间 */
    public Long getStartTime() {
        return startTime;
    }

    /** 设置Token创建时间 */
    public void setStartTime(Long startTime) {
        this.startTime = startTime;
    }

    /** 获取Token 登录时间 */
    public Long getLoginTime() {
        return loginTime;
    }

    /** 设置Token 登录时间 */
    public void setLoginTime(Long loginTime) {
        this.loginTime = loginTime;
    }

    /** 获取Token最后交互时间 */
    public Long getLastAccess() {
        return lastAccess;
    }

    /** 设置Token最后交互时间 */
    public void setLastAccess(Long lastAccess) {
        this.lastAccess = lastAccess;
    }

    /**
     * 获取Token 过期时间 
     * 
     * @return
     */
    public Long getExpireTime() {
        return expireTime;
    }

    /**
     * 设置Token 过期时间 
     * 
     * @param expireTime
     */
    public void setExpireTime(Long expireTime) {
        this.expireTime = expireTime;
    }

    /**
     * 获取Token 下一次过期时间
     * 
     * @return
     */
    public Long getExpireTimeNext() {
        return expireTimeNext;
    }

    /**
     * 设置Token 下一次过期时间
     * 
     * @param expireTimeNext
     */
    public void setExpireTimeNext(Long expireTimeNext) {
        this.expireTimeNext = expireTimeNext;
    }

    /**
     * 其他方式创建的时候的初始化
     * 
     * @return
     */
    public Token otherInit() {
        setStartTime(System.currentTimeMillis());
        setLastAccess(getStartTime());
        setExpireTime(TokenUtil.getExpireTime(getStartTime()));
        setExpireTimeNext(TokenUtil.getExpireTimeNext(getStartTime()));
        return this;
    }

    /**
     * 返回授予用户的权限,不能返回null
     */
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }

    /**
     * 获取帐号
     */
    @JSONField(serialize = false)
    @JsonIgnore
    @Override
    public String getUsername() {
        return getUser().getUsername();
    }

    /**
     * 获取密码
     */
    @JSONField(serialize = false)
    @JsonIgnore
    @Override
    public String getPassword() {
        return getUser().getPwd();
    }

    /**
     * 账户是否未过期,过期无法验证
     */
    @JSONField(serialize = false)
    @JsonIgnore
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    /**
     * 指定用户是否解锁,锁定的用户无法进行身份验证
     */
    @JSONField(serialize = false)
    @JsonIgnore
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    /**
     * 指示是否已过期的用户的凭据(密码),过期的凭据防止认证
     */
    @JSONField(serialize = false)
    @JsonIgnore
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    /**
     * 是否可用 ,禁用的用户不能身份验证
     */
    @JSONField(serialize = false)
    @JsonIgnore
    @Override
    public boolean isEnabled() {
        return true;
    }

}